#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <assert.h>

#include <vector>
#include <string>
#include <algorithm>

#ifndef WIN32
#include <sys/time.h>
#endif

#define DICT_MAGIC      "dictv1"

#define DICT_MAGIC_LEN  (sizeof(DICT_MAGIC) - 1)

/* 按 key 长度，把词分成多块，存储在文件在
 */

static int g_dict_data_pos = 0;

static FILE *g_dict_data_fp = NULL;

static char g_secret_table[] = "panxiqundemimahennanjiede";

static int g_secret_table_size = sizeof(g_secret_table) - 1;

#define LOWER_CHAR(c)                           \
    ((c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c)

bool
is_ascii(const char *s)
{
    while (*s) {
        if ((unsigned char) *s & (unsigned char) 0x80)
            return false;
        else
            ++s;
    }
    return true;
}

int
my_strcmp(const char *s1, const char *s2)
{
    if (!is_ascii(s1) || !is_ascii(s2))
        return strcmp(s1, s2);

    while (*s1 && *s2
           && (LOWER_CHAR(*s1) == LOWER_CHAR(*s2))) {
        ++s1;
        ++s2;
    }

    return (LOWER_CHAR(*s1) - LOWER_CHAR(*s2));
}

static int
dict_data_append(const char *data,
                 int         len)
{
    /* encode
     */
    static char *b = NULL;
    static int bl = 0;

    if (b == NULL) {
        bl = len;
        b = (char *) malloc (bl);
    }

    if (len > bl) {
        b = (char *) realloc (b, len);
        bl = len;
    }

    int i;
    for (i = 0; i < len; i++) {
        int ci = (g_dict_data_pos + i) % g_secret_table_size;

        b[i] = data[i] ^ g_secret_table[ci];
    }

    if (g_dict_data_fp) {
        if (fwrite(b, 1, len, g_dict_data_fp) != len) {
            fprintf(stderr, "write dict data file error: %s\n", strerror(errno));
            return -1;
        }
    }
    g_dict_data_pos += len;
    return 0;
}

struct IndexEntry {
    char *key;

    int   offset;

    int   len;
};

typedef std::vector<IndexEntry *> IndexEntryVector;

struct IndexBlockInfoW {
    /* 键的长度 + 0 结束符的长度不超大于 key_len_beg
     * 并且小于等于 key_len_end
     */
    int                 key_len_beg;

    int                 key_len_end;

    /* 存放所有属于此块的 Index 项
     */
    IndexEntryVector    vec;
};

/* 返回真表示 l 要放前面，r 放后面，否则相反
 */
struct SortIndexEntryFunctor {
    bool operator () (const IndexEntry *l,
                      const IndexEntry *r) const
    {
        /* NOTE:
         * strict   weak   ordering 的概念
         * 比较的时候，只有在 < 时返回 true，= or > 都返回 false
         * 如果这里用 <= 的话，会导致 std::sort 的 seg-fault.
         */
        return (my_strcmp(l->key, r->key) < 0);
    }
};

struct IndexManager {
    IndexBlockInfoW*            blocks;

    int                         nblocks;

    IndexManager()
    {
        blocks = new IndexBlockInfoW[1];
        blocks[0].key_len_beg = 0;
        blocks[0].key_len_end = 32;
        nblocks = 1;
    }

    ~IndexManager()
    {
        int i;
        for (i = 0; i < nblocks; i++) {
            int j;
            IndexBlockInfoW& block = blocks[i];
            IndexEntryVector& vec = block.vec;
            for (j = 0; j < vec.size(); j++) {
                IndexEntry *ent = vec[j];

                free(ent->key);
                delete ent;
            }
        }

        delete [] blocks;
    }

    int put_index(const char *key, int offset, int len)
    {
        int key_len = strlen(key);

        if (key_len == 0)
            return -1;

        // inlcluding zero-term byte.
        ++key_len;

        int i;
        for (i = 0; i < nblocks; i++) {
            if (blocks[i].key_len_beg <= key_len
                && key_len <= blocks[i].key_len_end) {
                break;
            }
        }
        if (i == nblocks) {
            fprintf(stderr, "key `%s' too long, store size is %d\n", key, key_len);
            return -1;
        }

        IndexEntry *ent = new IndexEntry();
        ent->key    = strdup(key);
        ent->offset = offset;
        ent->len    = len;
        blocks[i].vec.push_back(ent);

        return 0;
    }

    void sort_keys()
    {
        int i;
        for (i = 0; i < nblocks; i++) {
            IndexEntryVector& vec = blocks[i].vec;
            std::sort(vec.begin(), vec.end(), SortIndexEntryFunctor());
        }
    }

    int write_int(FILE *fp, unsigned int n)
    {
        unsigned char bytes[4];
        bytes[0] = (unsigned char) (n);
        bytes[1] = (unsigned char) (n >> 8);
        bytes[2] = (unsigned char) (n >> 16);
        bytes[3] = (unsigned char) (n >> 24);
        return (fwrite((const void *)bytes, 1, 4, fp) == 4) ? 0 : -1;
    }

    int write_int_mem(char *buf, unsigned int n)
    {
        unsigned char *bytes = (unsigned char *) buf;
        bytes[0] = (unsigned char) (n);
        bytes[1] = (unsigned char) (n >> 8);
        bytes[2] = (unsigned char) (n >> 16);
        bytes[3] = (unsigned char) (n >> 24);
        return 0;
    }

    int write_to_file(const char *fn)
    {
        FILE *fp = fopen(fn, "wb");
        if (fp == NULL) {
            fprintf(stderr, "create file `%s' failed: %s\n", fn, strerror(errno));
            return -1;
        }

        char             *str_buf;
        IndexEntry       *ent;
        int               header_size;
        int               idx_off;
        int               i, j, key_len;

        /* 签名与版本
         */
        if (fwrite(DICT_MAGIC, 1, DICT_MAGIC_LEN, fp) != DICT_MAGIC_LEN)
            goto write_error;

        /* 多少块
         */

        if (write_int(fp, nblocks) < 0)
            goto write_error;

        header_size = DICT_MAGIC_LEN + 4 + nblocks * (4 + 4 + 4);

        /* 块信息
         * - key长度 (4)
         * - 在 index 文件中的 offset 位置 (4)
         * - 有多少项 (4)
         */
        idx_off = 0;
        for (i = 0; i < nblocks; i++) {
            if (write_int(fp, blocks[i].key_len_end) < 0)
                goto write_error;
            if (write_int(fp, idx_off + header_size) < 0)
                goto write_error;
            if (write_int(fp, blocks[i].vec.size()) < 0)
                goto write_error;

            idx_off += (blocks[i].vec.size()
                        * (blocks[i].key_len_end + 4 + 4));
        }

        if (ftell(fp) != header_size) {
            fprintf(stderr, "file pos = %d, header size is %d\n", ftell(fp), header_size);
        }

        assert(ftell(fp) == header_size);

        /* 索引项
         * - key (key_len)
         * - data file offset (4)
         * - data file len (4)
         */

        /* 加密
         */
        for (i = 0; i < nblocks; i++) {
            int buflen = blocks[i].key_len_end + 8;
            str_buf = (char *) malloc (buflen);
            for (j = 0; j < blocks[i].vec.size(); j++) {
                ent = blocks[i].vec[j];
                key_len = blocks[i].key_len_end;
                memset(str_buf, 0, buflen);
                strcpy(str_buf, ent->key);

                write_int_mem(str_buf + key_len, ent->offset);
                write_int_mem(str_buf + key_len + 4, ent->len);

                int k;
                for (k = 0; k < buflen; k++) {
                    int ci = k % g_secret_table_size;
                    str_buf[k] = str_buf[k] ^ g_secret_table[ci];
                }

                for (k = strlen(ent->key); k < key_len; k++) {
                    str_buf[k] = (char) 0xff;

                    if (k + 1 == key_len)
                        str_buf[k] = strlen(ent->key);
                }

                if (fwrite(str_buf, 1, buflen, fp) != buflen)
                    goto write_error;
            }
            free(str_buf);
        }

        fclose(fp);
        return 0;

    write_error:
        fclose(fp);
        fprintf(stderr, "write index file error: %s\n", strerror(errno));
        return -1;
    }
};

struct IndexBlockInfoR {
    int                 key_len_beg;

    int                 key_len_end;

    int                 offset;

    int                 nents;
};

/* 发部出去的程序，密码表的存放方式
 */

static char _hide_[] = "D0E1M2I3M4A5H6E7N8N9A0N1J2I3E4D5E6P7A8N9X0I1Q2U3N4";

static int _hide_len_ = sizeof(_hide_) - 1;

struct DictManager {
    char*               idx_fn;

    char*               dat_fn;

    FILE*               idx_fp;

    FILE*               dat_fp;

    IndexBlockInfoR*    blocks;

    int                 nblocks;

    int read_int(FILE *fp, int *res)
    {
        unsigned char bytes[4];

        if (fread((void *)bytes, 1, 4, fp) != 4)
            return -1;

        unsigned int r = ((unsigned int)bytes[0] | (bytes[1] << 8U)
                          | (bytes[2] << 16U) | (bytes[3] << 24U));

        *res = (int) r;

        return 0;
    }

    int read_int_mem(char *buf, int *res)
    {
        unsigned char *bytes = (unsigned char *) buf;

        unsigned int r = ((unsigned int)bytes[0] | (bytes[1] << 8U)
                          | (bytes[2] << 16U) | (bytes[3] << 24U));

        *res = (int) r;

        return 0;
    }

    DictManager(const char *ifn, const char *dfn)
        : blocks(NULL)
        , nblocks(0)
    {
        idx_fn = strdup(ifn);
        dat_fn = strdup(dfn);

        idx_fp = fopen(ifn, "rb");
        dat_fp = fopen(dfn, "rb");

        if (idx_fp == NULL || dat_fp == NULL)
            return;

        char magic[DICT_MAGIC_LEN + 1];
        if (fread(magic, 1, DICT_MAGIC_LEN, idx_fp) != DICT_MAGIC_LEN) {
            fprintf(stderr, "read idx error: %s\n", strerror(errno));
            return;
        }

        magic[DICT_MAGIC_LEN] = 0;

        if (strcmp(magic, DICT_MAGIC)) {
            fprintf(stderr, "invalid magic, not index file\n");
            return;
        }

        if (read_int(idx_fp, &nblocks) < 0) {
            fprintf(stderr, "read error: %s\n", strerror(errno));
            return;
        }

        if (nblocks <= 0) {
            fprintf(stderr, "invalid number of blocks %d\n", nblocks);
            return;
        }

        int block_bytes = nblocks * (4 + 4 + 4);
        char *buf = (char *) malloc (block_bytes);
        if (fread(buf, 1, block_bytes, idx_fp) != block_bytes) {
            fprintf(stderr, "read error: %s\n", strerror(errno));
            free(buf);
            return;
        }

        int block_info_bytes = nblocks * sizeof(IndexBlockInfoR);
        blocks = (IndexBlockInfoR *) malloc (block_info_bytes);
        memset(blocks, 0, block_info_bytes);

        int last_key_len = 0;

        int i;
        for (i = 0; i < nblocks; i++) {
            char *p = buf + (i * (4 + 4 + 4));
            int   key_len;
            int   off, nents;
            read_int_mem(p, &key_len);
            read_int_mem(p + 4, &off);
            read_int_mem(p + 8, &nents);

            if (key_len <= last_key_len) {
                fprintf(stderr, "invalid key len in index file, %d, last is %d\n",
                        key_len, last_key_len);
                free(buf);
                free(blocks);
                blocks = NULL;
                return;
            }

            blocks[i].key_len_beg = last_key_len + 1;
            blocks[i].key_len_end = key_len;
            blocks[i].offset = off;
            blocks[i].nents = nents;

            last_key_len = key_len;
        }

        free(buf);
    }

    ~DictManager()
    {
        if (idx_fn)
            free(idx_fn);
        if (dat_fn)
            free(dat_fn);
        if (idx_fp)
            fclose(idx_fp);
        if (dat_fp)
            fclose(dat_fp);
        if (blocks)
            free(blocks);
    }

    int get_key_by_idx(const char *key,
                       char       *buf,
                       int         idx,
                       int         key_index)
    {
        int key_max_len = blocks[idx].key_len_end;

        int entry_size = (key_max_len) + 4 + 4;

        int pos = blocks[idx].offset + (key_index * entry_size);

        buf[0] = 0;

        if (fseek(idx_fp, pos, SEEK_SET) < 0) {
            fprintf(stderr, "index file seek %d failed\n", pos);
            return -1;
        }

        if (fread(buf, 1, entry_size, idx_fp) != entry_size) {
            fprintf(stderr, "index file read failed: %s\n", strerror(errno));
            return -1;
        }

        int len = (unsigned char) *(buf + entry_size - 9);

        if (len + 1 > entry_size - 8) {
            fprintf(stderr,
                    "invalid index format, key len is %d, but buffer size is %d\n",
                    len, entry_size - 8);
            return -1;
        }

        /* 解码 buf
         */
        int i;
        for (i = 0; i < entry_size; i++) {
            int real_len = _hide_len_ / 2;

            int ci = i % (real_len);

            if (ci < 8)
                ci = real_len - (8 - ci);
            else
                ci -= 8;

            ci *= 2;

            char x = _hide_[ci];

            x = x - 'A' + 'a';

            buf[i] = buf[i] ^ x;
        }

        buf[len] = 0;

        return 0;
    }

    /* 递归二分查找
     * x x x x
     * ^      ^
     * left   right
     *
     * 左下标是有效的，右下标是无效的。
     */
    char *binary_search(const char *key,
                        char       *buf,
                        int         idx,
                        int         left,
                        int         right,
                        int*        middle_idx)
    {
        if (left >= right)
            return NULL;

        int middle = (left + right) / 2;

        *middle_idx = middle;

        if (get_key_by_idx(key, buf, idx, middle) < 0)
            return NULL;

        int cmp = my_strcmp(key, buf);

        // found
        if (cmp == 0) {
            int off, len;

            int key_max_len = blocks[idx].key_len_end;

            int entry_size = (key_max_len) + 4 + 4;

            /* 往前找相同的 key
             */
            char *newbuf = (char *) malloc (entry_size);
            while (middle > 0) {
                if (get_key_by_idx(key, newbuf, idx, middle - 1) == 0
                    && my_strcmp(key, newbuf) == 0) {
                    memcpy(buf, newbuf, entry_size);
                    --middle;
                }
                else
                    break;
            }

            free(newbuf);

            *middle_idx = middle;

            read_int_mem(buf + entry_size - 8, &off);
            read_int_mem(buf + entry_size - 4, &len);

            if (len <= 0) {
                fprintf(stderr, "invalid length %d of data\n", len);
                return NULL;
            }

            if (fseek(dat_fp, off, SEEK_SET) < 0) {
                fprintf(stderr, "seek data file %d failed\n", off);
                return NULL;
            }

            char *res = (char *) malloc (len + 1);

            if (fread(res, 1, len, dat_fp) != len) {
                fprintf(stderr, "read data %d failed: %s\n", len, strerror(errno));
                free(res);
                return NULL;
            }

            res[len] = 0;

            /* 解码
             * 中间插入的数字是没用的。
             * panxiqun 这几只字母放在了后面。
             * 加密时用的是小写，_hide_ 里都变成了大写。
             */
            int i;
            for (i = 0; i < len; i++) {
                int real_len = _hide_len_ / 2;

                int ci = (off + i) % (real_len);

                if (ci < 8)
                    ci = real_len - (8 - ci);
                else
                    ci -= 8;

                ci *= 2;

                char x = _hide_[ci];

                x = x - 'A' + 'a';

                res[i] = res[i] ^ x;
            }

            return res;
        }
        else if (cmp < 0)
            right = middle;
        else
            left = middle + 1;

        return binary_search(key, buf, idx, left, right, middle_idx);
    }

    char *find_by_key(const char *key, char **potential, int *n)
    {
        int len = strlen(key);

        if (len == 0 || blocks == NULL) {
            *n = 0;
            return NULL;
        }

        ++len;

        /* 查找这个长度的 key 存放在哪一块中  */
        int i;
        for (i = 0; i < nblocks; i++) {
            if (blocks[i].key_len_beg <= len && len <= blocks[i].key_len_end)
                break;
        }

        if (i == nblocks) {
            fprintf(stderr, "not found, the key not belong to any block\n");
            if (n)
                *n = 0;
            return NULL;
        }

        if (blocks[i].nents <= 0) {
            fprintf(stderr, "the block empty\n");
            if (n)
                *n = 0;
            return NULL;
        }

        int entry_size = blocks[i].key_len_end + 4 + 4;

        char *buf = (char *) malloc (entry_size);

        int stop_at = 0;

        char *res = binary_search(key, buf, i, 0, blocks[i].nents, &stop_at);

        if (potential && n && *n > 0) {
            int b, e;

            /* 取 stop at 以下 N 个
             */
            b = stop_at;
            e = stop_at + *n;

            if (b < 0) {
                e += -b;
                b = 0;
            }

            if (e > blocks[i].nents) {
                int diff = e - blocks[i].nents;
                e = blocks[i].nents;
                b -= diff;
                if (b < 0)
                    b = 0;
            }

            //printf("geting potential from %d to %d, max is %d...\n",
            //       b, e, blocks[i].nents);

            int ngots = 0;
            while (b < e) {
                int idx_off = blocks[i].offset + (entry_size * b);

                ++b;

                if (fseek(idx_fp, idx_off, SEEK_SET) < 0) {
                    fprintf(stderr, "seek data file %d failed\n", idx_off);
                    *n = ngots;
                    break;
                }

                if (fread(buf, 1, entry_size, idx_fp) != entry_size) {
                    fprintf(stderr, "read index file failed: %s\n", strerror(errno));
                    *n = ngots;
                    break;
                }

                int klen = (unsigned char) *(buf + entry_size - 9);

                if (klen + 1 > entry_size - 8) {
                    fprintf(stderr,
                            "invalid index format, key len is %d, but buffer size is %d\n",
                            klen, entry_size - 8);
                    continue;
                }

                int zero_found = false;
                int j;
                for (j = 0; j < entry_size; j++) {
                    int real_len = _hide_len_ / 2;

                    int ci = j % (real_len);

                    if (ci < 8)
                        ci = real_len - (8 - ci);
                    else
                        ci -= 8;

                    ci *= 2;

                    char x = _hide_[ci];

                    x = x - 'A' + 'a';

                    buf[j] = buf[j] ^ x;
                }

                buf[klen] = 0;

                potential[ngots] = strdup(buf);

                ++ngots;
            }

            *n = ngots;
        }

        free(buf);

        return res;
    }
};

static void
get_random_string(char *buf, int len)
{
    int i;
    for (i = 0; i < len; i++) {
        int r = random();
        if (r < 0)
            r = -r;
        // scale to 'a' - 'z'
        const int nalphas = 'z' - 'a';
        r %= nalphas;
        r += 'a';
        buf[i] = (char) r;
    }
    buf[i] = 0;
}

static int
get_random_int(int left, int right)
{
    int r = random();

    if (r < 0)
        r = -r;

    int diff = right - left;

    assert(diff >= 0);

    r %= diff;

    r += left;

    return r;
}

/* make dict from input file `fn'
 * `fn' is the file has form like this
 *
 */
static int
dict_make(const char *fn,
          const char *idx_fn,
          const char *dat_fn)
{
    FILE *fp = fopen(fn, "rb");

    if (fp == NULL) {
        fprintf(stderr, "open `%s' failed: %s\n", fn, strerror(errno));
        return -1;
    }

    g_dict_data_fp = fopen(dat_fn, "wb");
    if (g_dict_data_fp == NULL) {
        fprintf(stderr, "create index file `%s' failed: %s\n", idx_fn, strerror(errno));
        fclose(fp);
        return 1;
    }

    IndexManager im;

    /* handle the line  */
    int     line_size;
    char   *lineptr          = NULL;
    size_t  line_buffer_size = 0;

    bool found_head_line = false;
    int  lineno = 0;

    printf("parsing...\n");

    for (;;) {
        while (!found_head_line) {
            line_size = getline(&lineptr, &line_buffer_size, fp);
            if (line_size > 0) {
                ++lineno;
                if (strstr(lineptr, "---headword---")) {
                    found_head_line = true;
                    break;
                }
            }
            else
                break;
        }
        if (!found_head_line)
            break;

        line_size = getline(&lineptr, &line_buffer_size, fp);
        if (line_size <= 0)
            break;

        ++lineno;

        // remove the line ending char or space
        std::string key, val;
        int         i;

        i = line_size - 1;
        while (i >= 0 && strchr(" \t\r\n", lineptr[i]))
            --i;

        if (i < 0) {
            fprintf(stderr, "invalid key at line %d\n", lineno);
            return -1;
        }

        key.assign(lineptr, i + 1);

        found_head_line = false;
        for (;;) {
            line_size = getline(&lineptr, &line_buffer_size, fp);
            if (line_size > 0) {
                ++lineno;
                if (strstr(lineptr, "---headword---")) {
                    found_head_line = true;
                    break;
                }
                else
                    val += lineptr;
            }
            else
                break;
        }

        if (val.size() > 0) {
            im.put_index(key.c_str(), g_dict_data_pos, val.size());
            dict_data_append(val.c_str(), val.size());
        }
    }

    int r = 0;

    printf("sorting keys\n");
    im.sort_keys();

    printf("writting index...\n");
    if (im.write_to_file(idx_fn) < 0)
        r = -1;

    fclose(g_dict_data_fp);
    fclose(fp);

    if (r == 0)
        printf("completed.\n");

    return r;
}

static int
do_test(int argc, char *argv[])
{
#if 0
    const int total = 1000;

    g_dict_data_fp = fopen("dict.dat", "wb");

    IndexManager manager;

    int  i;
    char key[40];
    char val[128];
    printf("putting key and data...\n");
    for (i = 0; i < total; i++) {
        int key_len = get_random_int(1, 20);
        assert(1 <= key_len && key_len <= 20);
        get_random_string(key, key_len);
        int val_len = get_random_int(1, 127);
        assert(1 <= val_len && val_len <= 127);
        get_random_string(val, val_len);

        manager.put_index(key, g_dict_data_pos, val_len);

        dict_data_append(val, val_len);
    }

    printf("sorting keys\n");
    manager.sort_keys();

    printf("writting index...\n");
    manager.write_to_file("dict.idx");

    fclose(g_dict_data_fp);

#endif

    DictManager dict("dict.idx", "dict.dat");

    printf("nblocks is %d\n", dict.nblocks);

    //dict.dump();

    const char *testkey;
    if (argc > 1)
        testkey = argv[argc - 1];
    else
        testkey = "whngy";

#ifndef WIN32
    struct timeval time_beg, time_end;

    gettimeofday(&time_beg, NULL);
#endif

    char *potential[10];
    int   n = 10;

    char *res = dict.find_by_key(testkey, potential, &n);

#ifndef WIN32
    gettimeofday(&time_end, NULL);

    int sec_diff = time_end.tv_sec - time_beg.tv_sec;

    int us_diff = sec_diff * 1000000 + time_end.tv_usec;

    us_diff -= time_beg.tv_usec;

    printf("time for find is: %d us\n", us_diff);
#endif

    if (res)
        printf("found: `%s'\n", res);
    else {
        printf("dump potential %d\n", n);
        int i;
        for (i = 0; i < n; i++) {
            printf(" -> `%s'\n", potential[i]);
            free(potential[i]);
        }
    }

    return 0;
}

#ifdef DICT_MAKE

static std::string g_idx_fn;

static std::string g_dat_fn;

static int
_handle_opt_args(int argc, char *argv[])
{
    int i;
    for (i = 1; i < argc; i++) {
        std::string o = argv[i];
        if (o == "-oi") {
            if (i + 1 < argc)
                g_idx_fn = argv[++i];
        }
        else if (o == "-od") {
            if (i + 1 < argc)
                g_dat_fn = argv[++i];
        }
        else if (o == "-o") {
            if (i + 1 < argc) {
                std::string prefix = argv[++i];
                g_idx_fn = prefix + ".idx";
                g_dat_fn = prefix + ".dat";
            }
        }
        else
            break;
    }
    return i;
}

int main(int argc, char *argv[])
{
    srand(time(NULL));

    int i = _handle_opt_args(argc, argv);

    if (i >= argc) {
        fprintf(stderr, "%s [options] raw-dict-file\n", argv[0]);
        fprintf(stderr, "   -o  prefix, output prefix.idx prefix.dat\n");
        fprintf(stderr, "   -oi index file\n");
        fprintf(stderr, "   -od data file\n");
        return 1;
    }

    if (g_idx_fn.empty())
        g_idx_fn = "dict.idx";
    if (g_dat_fn.empty())
        g_dat_fn = "dict.dat";

    const char *raw_file = argv[i];

    return dict_make(raw_file, g_idx_fn.c_str(), g_dat_fn.c_str());
}

#endif

#ifdef DICT_FIND

int main(int argc, char *argv[])
{
    srand(time(NULL));

    if (argc < 4) {
        fprintf(stderr, "%s idx-file dat-file word\n", argv[0]);
        return 1;
    }

    const char *idx_fn = argv[1];
    const char *dat_fn = argv[2];
    const char *word   = argv[3];

    DictManager dm(idx_fn, dat_fn);

    if (dm.blocks == NULL)
        return 1;

    char *p[10];
    int   n = 10;

    char *res = dm.find_by_key(word, p, &n);

    if (res)
        printf("%s", res);
    else
        printf("not found\n");

    int i;
    for (i = 0; i < n; i++) {
        printf(" -> %s\n", p[i]);
    }

    return 0;
}

#endif
